home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 42
/
Amiga Format AFCD42 (Issue 126, Aug 1999).iso
/
-serious-
/
comms
/
other
/
slrn
/
slrn_src
/
src
/
slrnpull.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-05-14
|
52KB
|
2,529 lines
/* -*- mode: C; mode: fold -*- */
/* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
*
* This file is part of slrn.
*
* Slrn is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Slrn is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with Slrn; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#define SLRNPULL_CODE
#include "slrnfeat.h"
/*{{{ System Includes */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <time.h>
#include <sys/stat.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <ctype.h>
#ifndef S_ISREG
# define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG))
#endif
#include <slang.h>
#include "jdmacros.h"
/*}}}*/
/*{{{ Local Includes */
#include "ttymsg.h"
#include "util.h"
#include "sltcp.h"
#include "nntplib.h"
#include "nntpcodes.h"
#include "slrndir.h"
#include "version.h"
#include "score.c"
#include "xover.c"
#undef SLRN_HAS_MSGID_CACHE
#define SLRN_HAS_MSGID_CACHE 1
#include "hash.c"
/*}}}*/
/*{{{ slrnpull global variables and structures */
#ifndef SLRNPULL_ROOT_DIR
# define SLRNPULL_ROOT_DIR "/var/spool/news/slrn"
#endif
#ifndef SLRNPULL_CONF
# define SLRNPULL_CONF "slrnpull.conf"
#endif
#ifndef SLRNPULL_OUTGOING_DIR
# define SLRNPULL_OUTGOING_DIR "out.going"
#endif
#if SLRNPULL_USE_SETGID_POSTS
# define OUTGOING_DIR_MODE (0777 | 03000)
#else
# define OUTGOING_DIR_MODE (0777 | 01000)
#endif
#ifndef SLRNPULL_SCORE_FILE
# define SLRNPULL_SCORE_FILE "score"
#endif
#ifndef SLRNPULL_NEWS_DIR
# define SLRNPULL_NEWS_DIR "news"
#endif
#ifndef SLRNPULL_LOGFILE
# define SLRNPULL_LOGFILE "log"
#endif
#ifndef SLRNPULL_OUTGOING_BAD_DIR
# define SLRNPULL_OUTGOING_BAD_DIR "rejects"
#endif
#ifndef SLRNPULL_OUTGOING_DIR_MODE
# define SLRNPULL_OUTGOING_DIR_MODE (0777 | 01000)
#endif
static int Exit_Code;
#define SLRN_EXIT_UNKNOWN 1
#define SLRN_EXIT_BAD_USAGE 2
#define SLRN_EXIT_CONNECTION_FAILED 3
#define SLRN_EXIT_CONNECTION_LOST 4
#define SLRN_EXIT_SIGNALED 5
#define SLRN_EXIT_MALLOC_FAILED 10
#define SLRN_EXIT_FILEIO 20
char *SlrnPull_Dir = SLRNPULL_ROOT_DIR;
char *SlrnPull_Spool_News_Dir;
char *Group_Min_Max_File; /* relative to group dir */
char *Overview_File; /* relative to group dir */
char *Outgoing_Dir;
char *Outgoing_Bad_Dir;
char *New_Groups_File = "new.groups";
char *New_Groups_Time_File = "new.groups-time";
char *Data_Dir = "data";
static char *Active_File = "active";
static int Stdout_Is_TTY;
static char *Active_Groups_File;
static time_t Start_Time;
#define CREATE_OVERVIEW 1
static int handle_interrupts (void);
typedef struct _Active_Group_Type /*{{{*/
{
unsigned int flags;
/* Unfortunately, three different sets of article ranges are required.
* Ideally, only one would be required but this does not seem to be
* possible. This is because the articles in the spool directory
* created by slrnpull do not expire when the articles on the server
* expire. In addition, slrnpull removes duplicate articles so that
* the articles present on the server may not actually be present in the
* spool directory.
*
* The main problem is that it appears that some servers will reuse
* article numbers from articles that have been cancelled. The spool
* directory created by slrnpull does not know about cancel messages,
* which means that the same article number can refer to two different
* articles. The ultimate solution would be for slrnpull to use its own
* numbering scheme that is independent of the server's. This would mean
* caching all message-ids and stripping Xref headers from the articles
* that are received from the server. At first sight it would appear that
* new Xref headers would have to be generated for the .overview files but
* since slrnpull removes duplicates, this should not be necessary. A
* major advantage of this approach is that one could merge multiple feeds.
* A rough estimate of the size of the message-id cache is 100 * 500 * 80,
* or 4,000,000 bytes assuming 100 newsgroups with 500 articles per group
* and a message id of 80 characters. Of course that number would be
* smaller if Pine were eliminated.
*/
unsigned int min, max; /* range of articles that slrnpull has
already dealt with */
unsigned int active_min, active_max;/* article numbers that are in spool dir */
unsigned int server_min; /* artcle numbers that server reports */
unsigned int server_max;
unsigned int max_to_get; /* if non-zero, get only this many */
unsigned int expire_days; /* if zero, no expiration */
#define MAX_GROUP_NAME_LEN 80
char name [MAX_GROUP_NAME_LEN + 1];
char dirname [MAX_GROUP_NAME_LEN + 1];
struct _Active_Group_Type *next;
}
/*}}}*/
Active_Group_Type;
static char *Current_Newsgroup;
static Active_Group_Type *Active_Groups;
static Active_Group_Type *Active_Groups_Tail;
/*}}}*/
static FILE *MLog_Fp;
static FILE *ELog_Fp;
static void write_timestamp (FILE *fp) /*{{{*/
{
struct tm *tms;
time_t tloc;
time (&tloc);
tms = localtime (&tloc);
fprintf (fp, "%02d/%02d/%04d %02d:%02d:%02d ",
tms->tm_mon + 1, tms->tm_mday, 1900 + tms->tm_year,
tms->tm_hour, tms->tm_min, tms->tm_sec);
}
/*}}}*/
static void write_log (FILE *fp, char *pre, char *buf)
{
write_timestamp (fp);
if (pre != NULL) fputs (pre, fp);
fputs (buf, fp);
fputc ('\n', fp);
fflush (fp);
}
static void va_log (FILE *fp, char *pre, char *fmt, va_list ap) /*{{{*/
{
char buf[2048];
vsprintf (buf, fmt, ap);
write_log (fp, pre, buf);
if ((Stdout_Is_TTY == 0) || (fp == stdout) || (fp == stderr))
return;
if (fp == MLog_Fp) fp = stdout; else fp = stderr;
write_log (fp, pre, buf);
}
/*}}}*/
static void log_message (char *fmt, ...) /*{{{*/
{
va_list ap;
va_start (ap, fmt);
va_log (MLog_Fp, NULL, fmt, ap);
va_end (ap);
}
/*}}}*/
static void log_error (char *fmt, ...) /*{{{*/
{
va_list ap;
va_start (ap, fmt);
va_log (ELog_Fp, "***", fmt, ap);
va_end (ap);
}
/*}}}*/
static void va_log_error (char *fmt, va_list ap) /*{{{*/
{
va_log (ELog_Fp, "***", fmt, ap);
}
/*}}}*/
static void va_log_message (char *fmt, va_list ap) /*{{{*/
{
va_log (MLog_Fp, NULL, fmt, ap);
}
/*}}}*/
static Active_Group_Type *find_group_type (char *name) /*{{{*/
{
Active_Group_Type *g;
g = Active_Groups;
while (g != NULL)
{
if (!strcmp (name, g->name))
break;
g = g->next;
}
return g;
}
/*}}}*/
static Active_Group_Type *add_group_type (char *name) /*{{{*/
{
Active_Group_Type *g;
g = (Active_Group_Type *) slrn_malloc (sizeof (Active_Group_Type), 1, 1);
if (g == NULL)
return NULL;
strncpy (g->name, name, MAX_GROUP_NAME_LEN); /* null terminated
* by construction */
if (Active_Groups_Tail != NULL)
Active_Groups_Tail->next = g;
else
Active_Groups = g;
Active_Groups_Tail = g;
return g;
}
/*}}}*/
#if defined(__MINGW32__)
# define MKDIR(x,y) mkdir(x)
#else
# define MKDIR(x,y) mkdir(x,y)
#endif
static int do_mkdir (char *dir, int err) /*{{{*/
{
if (0 == MKDIR (dir, 0777))
{
log_message ("Created dir %s.", dir);
return 0;
}
if (errno == EEXIST)
return 0;
if (err)
log_error ("Unable to create directory %s. (errno = %d)", dir, errno);
return -1;
}
/*}}}*/
static FILE *open_group_min_max_file (Ac